package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.VO.WmNewsVO;
import com.heima.model.common.constants.mededia.WemediaConstants;
import com.heima.model.common.dtos.*;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.mededia.pojo.WmNews;
import com.heima.model.common.mededia.pojo.WmNewsMaterial;
import com.heima.model.common.mededia.pojo.WmUser;
import com.heima.model.common.threadlocal.WmThreadLocalUtils;
import com.itheima.common.constants.message.NewsAutoScanConstants;
import com.itheima.common.constants.message.NewsUpOrDownConstants;
import com.itheima.common.constants.message.PublishArticleConstants;
import com.itheima.common.exception.CustException;
import com.itheima.wemedia.mapper.WMuserMapper;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.service.WMUserService;
import com.itheima.wemedia.service.WnNewsService;
import io.jsonwebtoken.lang.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WnNewsServiceImpl extends ServiceImpl<WmNewsMapper,WmNews> implements WnNewsService {
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private WnNewsService wnNewsService;
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private WMuserMapper wMuserMapper;
    @Value("${file.oss.web-site}")
    String webSite;
    @Override
    public ResponseResult findList(WmNewsPageReqDTO dto) {
        //校验参数
        if (dto == null ){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        //业务需求
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
//        1. 如果有文章标题，按照文章标题模糊查询
        wrapper.like(StringUtils.isNotBlank(dto.getKeyword()),WmNews::getTitle,dto.getKeyword());
//        2. 如果有频道信息，按照频道ID查询
        wrapper.eq(dto.getChannelId()!= null,WmNews::getChannelId,dto.getChannelId());
//        3. 如果有文章状态，按照状态信息进行查询
        wrapper.eq(dto.getStatus()!=null,WmNews::getStatus,dto.getStatus());
//        4. 如果开始时间，结束时间不为空按照时间区间查询
        //开始时间
        wrapper.ge(dto.getBeginPubDate()!=null,WmNews::getPublishTime,dto.getBeginPubDate());
        //结束时间
        wrapper.le(dto.getEndPubDate()!= null,WmNews::getPublishTime,dto.getEndPubDate());
//        5. 按照登录用户ID去查询
        WmUser user = WmThreadLocalUtils.getUser();
        if (user==null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        wrapper.eq(WmNews::getUserId,user.getId());
//        6. 按照创建时间降序
        wrapper.orderByDesc(WmNews::getCreatedTime);
//        7. 分页查询，返回结果设置host  地址 为图片访问前缀
        IPage<WmNews> iPage = new Page<>(dto.getPage(), dto.getSize());
        IPage<WmNews> pageResult = page(iPage, wrapper);
        List<WmNews> records = pageResult.getRecords();
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), pageResult.getTotal(), records);
        result.setHost(webSite);
        return result;
    }

    @Override
    public ResponseResult submit(WmNewsDTO dto) {
//        1. 参数校验
        if (StringUtils.isBlank(dto.getContent())){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"文章内容不能为空");
        }
        //检查是否登录
        WmUser user = WmThreadLocalUtils.getUser();
        if (user==null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //保存或修改文章
        //将dto中的数据设置到WnNews中
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto,wmNews);
        //如果文章布局是自动，需要设置为null
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            wmNews.setType(null);//因为wmNews表中type不能为负数
        }
        // 处理dto参数 images封面集合 转换成 字符串 传来的参数images是一个数组
        String images = tostring(dto.getImages());
        wmNews.setImages(images);
        wmNews.setUserId(user.getId());
        saveorUpdate(wmNews);
        //如果是草稿直接返回  业务结束
        if (dto.getType().equals(WemediaConstants.WM_NEWS_DRAFT_STATUS)){
            ResponseResult.okResult();
        }
//        1. 关联文章和素材关系表
//                - 关联内容中的图片与素材的关系
//                - 关联封面中的图片与素材的关系
//        封面图片如果选择是自动需要从内容中截图图片做为封面图片
//        截取规则为：
//        - 内容图片的个数小于等于2  则为单图截图一张图
//                - 内容图片大于2，则为多图，截图三张图
//                - 内容中没有图片，则为无图
        //关联内容中图片与素材的关系
        // TODO 3.1 抽取文章中关联的图片路径
        List<Map> mapList = JSON.parseArray(dto.getContent(), Map.class);//解析集合类json字符串 将json字符串转化成对应的类型对象
        List<String> list = getUrls(mapList);

        // TODO 3.2 关联文章内容中的图片和素材关系
        //查询图片对应的素材id
        if (!CollectionUtils.isEmpty(list)){
            saveInfo(user, wmNews, list);
        }
        // TODO 3.3 关联文章封面中的图片和素材关系  封面可能是选择自动或者是无图

        List<String> dtoImages = dto.getImages();
        int size = list.size();
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){//自动
            if (size<=2 && size>0){//单图截一张图
                dtoImages=list.stream().limit(1).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            }else if (size>2){//多图截三张
                dtoImages=list.stream().limit(3).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE );
            }else {
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }
            if ( dtoImages.size()>0){
                wmNews.setImages(tostring(dtoImages));
            }
            updateById(wmNews);
        }
        if (dtoImages.size()>0){
            dtoImages=dtoImages.stream().map(x->x.replace(webSite,"").replace(" ","")).collect(Collectors.toList());
            saveInfo(user,wmNews,dtoImages);
        }





//        2. 封装返回成功结果
        // 3.4 发送待审核消息
        rabbitTemplate.convertAndSend(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE,wmNews.getId());
        log.info("成功发送 待审核消息 ==> 队列:{}, 文章id:{}",NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE,wmNews.getId());
        





        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult selectById(Integer id) {
        if (id == null){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = getById(id);
        if (wmNews == null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        ResponseResult responseResult = ResponseResult.okResult(wmNews);
        responseResult.setHost(webSite);
        return responseResult;
    }

    @Override
    public ResponseResult delNewsById(Integer id) {
        //校验参数
        if (id==null){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (WmThreadLocalUtils.getUser()==null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //先查询
        WmNews wmNews = getById(id);
        if (wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //判断文章状态
        if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode()) && wmNews.getEnable().equals(WemediaConstants.WM_NEWS_UP)){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"文章已发布,不能删除");
        }
        //先删除关系表
        wmNewsMaterialMapper.delete(new LambdaQueryWrapper<WmNewsMaterial>().eq(WmNewsMaterial::getNewsId,id));
        //再删除文章表
        removeById(id);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult downOrUp(WmNewsDTO dto) {
        //校验参数
        if (dto==null){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (dto.getEnable()==null || (!dto.getEnable().equals(WemediaConstants.WM_NEWS_UP) && !dto.getEnable().equals(WemediaConstants.WM_NEWS_DOWN))){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (WmThreadLocalUtils.getUser()==null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //

        WmNews wmNews = getById(dto.getId());
        if (wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW);
        }
        wmNews.setEnable(dto.getEnable());
        updateById(wmNews);
        if (wmNews.getArticleId()!=null) {
            if(dto.getEnable().equals(WemediaConstants.WM_NEWS_UP)){
                // 上架消息
                rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_OR_DOWN_EXCHANGE,
                        NewsUpOrDownConstants.NEWS_UP_ROUTE_KEY,wmNews.getArticleId());
            }else {
                // 下架消息
                rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_OR_DOWN_EXCHANGE,
                        NewsUpOrDownConstants.NEWS_DOWN_ROUTE_KEY,wmNews.getArticleId());
            }
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult selectList(NewsAuthDTO dto) {
        //校验参数
        dto.checkParam();
        Integer currentPage = dto.getPage();
        dto.setPage((dto.getPage()-1)*dto.getSize());
        if (StringUtils.isNotBlank(dto.getTitle())){
            dto.setTitle("%"+dto.getTitle()+"%");
        }
        // 分页查询
        List<WmNewsVO> listAndPage = wmNewsMapper.findListAndPage(dto);
        //统计多少条数据
        long count = wmNewsMapper.findListCount(dto);
        //返回数据
        ResponseResult result = new PageResponseResult(currentPage,dto.getSize(),count,listAndPage);
        result.setHost(webSite);
        return result;


    }

    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        //1参数检查
        if(id == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询文章信息
        WmNews wmNews = getById(id);
        if(wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //查询作者
        WmUser wmUser = null;
        if (wmNews.getUserId()!=null){
            wmUser = wMuserMapper.selectById(wmNews.getUserId());
        }
        //封装结果返回
        WmNewsVO wmNewsVo = new WmNewsVO();
        BeanUtils.copyProperties(wmNews,wmNewsVo);
        if(wmUser != null){
            wmNewsVo.setAuthorName(wmUser.getName());
        }
        ResponseResult result = ResponseResult.okResult(wmNewsVo);
        result.setHost(webSite);
        return result;

    }

    @Override
    public ResponseResult updateStatus(Short status,NewsAuthDTO dto) {
        //1.参数检查
        if(dto == null || dto.getId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.查询文章
        WmNews wmNews = getById(dto.getId());
        if(wmNews == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 检查文章状态 不能为9  已发布
        if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"文章已发布");
        }
        //3.修改文章状态
        wmNews.setStatus(status);
        if(StringUtils.isNotBlank(dto.getMsg())){
            wmNews.setReason(dto.getMsg());
        }
        updateById(wmNews);

        // TODO 通知定时发布文章
        // 发布时间
        long publishTime = wmNews.getPublishTime().getTime();
        // 当前时间
        long nowTime = new Date().getTime();
        long remainTime = publishTime - nowTime;
        // 发布文章
        rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE
                , PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY
                , wmNews.getId()
                , (message)->{                              // 延时消息 必设置
                    message.getMessageProperties().setHeader("x-delay",remainTime<=0?0:remainTime);
                    return message;
                }
        );
        log.info("立即发布文章通知成功发送，文章id : {}", wmNews.getId());

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    private void saveInfo(WmUser user, WmNews wmNews, List<String> list) {
        List<Integer> ids = wmMaterialMapper.selectRelationsIds(list, user.getId());
        //存中间表
        if (CollectionUtils.isEmpty(ids) || ids.size()< list.size()){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"素材缺失,保存文章失败");
        }
        wmNewsMaterialMapper.saveRlations(ids, wmNews.getId(),WemediaConstants.WM_CONTENT_REFERENCE);// 保存关系表
    }

    private List<String> getUrls(List<Map> mapList) {
        List<String> list = mapList.stream()
                .filter(value -> value.get("type").equals("image"))
                .map(url -> (String) url.get("value"))//将Map中的value类型转为String 方便后续操作
                .map(url -> url.replace(webSite, "").replace(" ", ""))//去掉前缀
                .distinct()//去重
                .collect(Collectors.toList());
        return list;
    }

    private void saveorUpdate(WmNews wmNews) {
        wmNews.setCreatedTime(new Date());
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable(WemediaConstants.WM_NEWS_UP);
        if (wmNews.getId() == null ){
            //保存
            save(wmNews);
        }else {
            //修改 先删除关联表
            wmNewsMaterialMapper.delete(new LambdaQueryWrapper<WmNewsMaterial>().eq(WmNewsMaterial::getNewsId,wmNews.getId()));
            updateById(wmNews);
        }
    }

    private String tostring(List<String> images) {
        return images.stream().map((url)->url.replace(webSite,"")).collect(Collectors.joining(","));

    }
}
